#pragma once
#include <iostream>
#include <sys/epoll.h>
#include <functional>
#include "sock.hpp"
#include "err.hpp"

namespace epollServer
{
    using func_t = std::function<std::string (const std::string&)>;
    class EpollServer
    {
        const static int defaultport = 8080;
        const static int default_val = -1;                  // fd数组的默认值
        const static int default_size = sizeof(fd_set) * 8; // select可以管理的文件描述符个数
        const static int num = 32;
    public:
        EpollServer(func_t cb, int port = defaultport)
        : _port(port), _listensock(default_val) ,_cb(cb), _epfd(default_val) ,_num(num)
        {}
        ~EpollServer()
        {
            close(_listensock);
        }
        void initServer()
        {

            // 1.创建套接字
            _listensock = Sock::Socket();

            // 1.5取消time_wait状态的绑定冷却时间
            int opt = 1;
            setsockopt(_listensock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));

            // 2.绑定ip和端口
            Sock::Bind(_listensock, _port);

            // 3.设置监听状态
            Sock::Listen(_listensock);

            // 4.创建epoll模型
            _epfd = epoll_create(99);
            if(_epfd < 0)
            {
                logMessage(FATAL, "epoll_create err, err string: %s", strerror(errno));
                exit(EPOLL_CREATE_ERR);
            }
            else logMessage(NORMAL, "epoll_create success fd: %d", _epfd);

            // 5.添加_listensock到epoll模型中
            struct epoll_event event;
            event.events = EPOLLIN | EPOLLET;
            event.data.fd = _listensock;
            int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, _listensock, &event);
            if(n == 0)
            {
                logMessage(NORMAL, "add listensock to epoll success");
            }
            else if(n < 0)
            {
                logMessage(FATAL, "add listensock to epoll err, err string: %s", strerror(errno));
                exit(ADD_LISTEN_ERR);
            }
            else 
            {
                //......
            }


            //申请就绪事件的空间
            _epevents = new struct epoll_event[_num];
        }

        void start()
        {
            int timeout = 1000;
            for( ; ; )
            {
                int n = epoll_wait(_epfd, _epevents, _num, timeout);
                switch (n)
                {
                case 0:
                    logMessage(NORMAL, "timeout....");
                    break;
                case -1:
                    logMessage(WARNING, "epoll_wait err code: %d err string: %s", errno, strerror(errno));
                    break;
                default:
                    logMessage(NORMAL, "have event ready");
                    HandlerEvent(n);
                    break;
                }

            }
        }

        void Accepter()
        {

            // 处理监听事件
            std::string clientip;
            uint16_t clientport;
            // 不会等待，直接获取连接
            int sock = Sock::Accept(_listensock, &clientip, &clientport);
            if (sock >= 0)
            {
                logMessage(NORMAL, "accept a new client, clientip: %s, clientport: %d", clientip.c_str(), clientport);
            }
            struct epoll_event events;
            events.events = EPOLLIN;
            events.data.fd = sock;
            int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, sock, &events);
            if(n != 0)
            {
                logMessage(ERROR, "epoll_ctl_add failed code: %d err string: %s", errno, strerror(errno));
            }

        }

        //处理客户端连接请求
        void Recver(int sock)
        {
            char buffer[1024];
            int n = recv(sock, buffer, sizeof(buffer) - 1, 0);
            if(n > 0)
            {
                buffer[n] = 0;
                logMessage(DEBUG, "echo# %s", buffer);

                std::string response = _cb(buffer);

                send(sock, response.c_str(), response.size(), 0);
            }
            else if(n == 0)
            {
                logMessage(NORMAL, "client quit");
                epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);
                close(sock);

            }
            else
            {
                logMessage(ERROR, "client quit");
                epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);
                close(sock);
            }
        }


        //处理select监视成功后的新任务
        void HandlerEvent(int num)
        {
            for(int i = 0; i < num; ++i)
            {
                int sock = _epevents[i].data.fd;
                uint32_t events = _epevents[i].events;
                if(sock == _listensock && (events & EPOLLIN))
                {
                    //listensock的读事件就绪
                    Accepter();
                }
                else if(events & EPOLLIN)
                {
                    Recver(sock);
                }
                else
                {}
                
            }
        }
        void Print()
        {
            
        }
        

    private:
        int _listensock;
        int _port;
        func_t _cb; //回调方法：由上层提供的业务逻辑
        int _epfd; 

        struct epoll_event* _epevents;
        int _num;
    };
}